package com.example.sys.job.service;

import com.example.core.mapping.Mapping;
import com.example.core.po.BasePo;
import com.example.core.service.BaseServiceImpl;
import com.example.sys.job.dao.SysJobDao;
import com.example.sys.job.listener.SysJobLogJobListener;
import com.example.sys.job.mapping.SysJobMapping;
import com.example.sys.job.po.SysJob;
import com.example.sys.job.vo.SysJobVo;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;

@Service
public class SysJobServiceImpl extends BaseServiceImpl<SysJobDao, SysJob, SysJobVo> implements SysJobService, InitializingBean {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public Class<? extends Mapping> getMappingClass() {
        return SysJobMapping.class;
    }

    @Resource
    private Scheduler scheduler;

    @Override
    public String add(SysJobVo vo) throws Exception {
        vo.setType("2");
        SysJob sysJob = toPo(vo);
        sysJob.setEnabled(true);
        save(sysJob);
        this.addJob(sysJob);
        return sysJob.getId();
    }

    @Override
    public void runOnce(Long id) throws Exception {
        SysJob sysJob = this.getById(id);
        if (sysJob != null) {
            JobKey jobKey = new JobKey(sysJob.getId(), JOB_GROUP_KEY);
            scheduler.triggerJob(jobKey);
        }
    }


    @Override
    public Date addJob(SysJob job) throws Exception {
        Date nextTime = getNextTime(new Date(), job.getCron());
        JobBuilder jobBuilder = JobBuilder.newJob((Class<? extends Job>) Class.forName(job.getJobClass())).withIdentity(job.getId(), JOB_GROUP_KEY);
        jobBuilder.usingJobData(JOBID, job.getId());
        jobBuilder.usingJobData(JOBCLASS, job.getJobClass());
        JobDetail jobDetail = jobBuilder.build();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron()).withMisfireHandlingInstructionDoNothing();
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getId(), JOB_GROUP_KEY).startAt(nextTime).withSchedule(scheduleBuilder).build();
        return scheduler.scheduleJob(jobDetail, trigger);
    }

    @Override
    public void pauseJob(SysJob job) throws Exception {
        JobKey jobKey = new JobKey(job.getId(), JOB_GROUP_KEY);
        job.setEnabled(false);
        scheduler.pauseJob(jobKey);
        this.saveOrUpdate(job);
    }

    @Override
    public void resumeJob(SysJob job) throws Exception {
        JobKey jobKey = new JobKey(job.getId(), JOB_GROUP_KEY);
        job.setEnabled(true);
        scheduler.resumeJob(jobKey);
        this.saveOrUpdate(job);
    }

    @Override
    public void modifyJob(SysJob job) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getId(), JOB_GROUP_KEY);
        JobKey jobKey = new JobKey(job.getId(), JOB_GROUP_KEY);
        if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron()).withMisfireHandlingInstructionDoNothing();
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey, trigger);
            this.saveOrUpdate(job);
        }
    }


    @Override
    public void modifyJob(SysJobVo sysJobVo) throws Exception {
        SysJob sysJob = this.toPo(sysJobVo);
        sysJob.setEnabled(Boolean.TRUE);
        this.modifyJob(sysJob);
        this.saveOrUpdate(sysJob);
    }

    @Override
    public Date getNextTime(Date startTime, String cron) throws Exception {
        CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cron);
        return cronSequenceGenerator.next(startTime);
    }

    @Override
    public SysJob getByJobClass(String jobClass) throws Exception {
        return getBaseMapper().getByJobClass(jobClass);
    }


    /*****
     *
     * 创建任务的cron，这是一次性执行的
     * @param date
     * @return
     */
    @Override
    public String createCronExpression(Date date) {
        StringBuffer cronExpression = new StringBuffer();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        cronExpression.append(calendar.get(Calendar.SECOND) + " ").append(calendar.get(Calendar.MINUTE) + " ").append(calendar.get(Calendar.HOUR_OF_DAY) + " ").append(calendar.get(Calendar.DATE) + " ").append((calendar.get(Calendar.MONTH) + 1) + " ").append("?");
        return cronExpression.toString();
    }


    /****
     *
     * 定义任务间隔分钟执行的 0 0/5 * * * ?
     * @param minute
     * @return
     */
    @Override
    public String createCronExpression(int minute) {
        StringBuffer stringBuffer = new StringBuffer("0 0/");
        stringBuffer.append(minute);
        stringBuffer.append(" * * * ?");
        return stringBuffer.toString();
    }


    /****
     *
     * 创建用户定时任务
     * @param jobClass
     * @param po
     * @param runTime
     * @throws Exception
     */
    @Override
    public void createUserJob(Class<? extends Job> jobClass, BasePo po, Date runTime) throws Exception {
        String cron = createCronExpression(runTime);
        JobBuilder jobBuilder = JobBuilder.newJob(jobClass).withIdentity(po.getId(), JOB_GROUP_KEY);
        jobBuilder.usingJobData(JOBID, po.getId());
        jobBuilder.usingJobData(MODELID, po.getId());
        jobBuilder.usingJobData(MODELNAME, po.getClass().getName());
        JobDetail jobDetail = jobBuilder.build();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing();
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(po.getId(), JOB_GROUP_KEY).startAt(new Date()).withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, trigger);
    }


    /***
     * 修改用户定时任务
     * @param po
     * @param newTime
     * @throws Exception
     */
    @Override
    public void modifyUserJob(BasePo po, Date newTime) throws Exception {
        String cron = createCronExpression(newTime);
        TriggerKey triggerKey = TriggerKey.triggerKey(po.getId(), JOB_GROUP_KEY);
        JobKey jobKey = new JobKey(po.getId(), JOB_GROUP_KEY);
        if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing();
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey, trigger);
        }
    }

    /****
     * model模块的id，可以指定删除定时任务.
     * @param id
     * @throws Exception
     */
    @Override
    public void deleteUserJob(String id) throws Exception {
        JobKey jobKey = new JobKey(id, JOB_GROUP_KEY);
        scheduler.deleteJob(jobKey);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        this.scheduler.getListenerManager().addJobListener(new SysJobLogJobListener());
    }
}
